<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Account\Ctl;

use Srv\Apps\Apis\Common\Ctl\DeviceCtl;
use Srv\Apps\Apis\Common\DefCtl\DefChannelCtl;
use Srv\Apps\Apis\Common\DefCtl\DefDeviceLangCtl;
use Srv\Apps\Apis\Common\DefCtl\DefPlatformCtl;
use Srv\Apps\Apis\Common\IdxCtl\IdxIp;
use Srv\Apps\Proto\VO\TokenVO;
use Srv\Libs\Common\CommNet;
use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\AuthData;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Frame\RequestHeader;
use Srv\Libs\Storage\DataMysql;

final class TokenCtl extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write

    /**
     * @return static
     * tag
     */
    final public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param int $admUserId
     * @param int $nonceId
     * @return bool
     * 登出令牌
     */
    public function signOutToken(int $admUserId, int $nonceId):bool
    {
        if($admUserId < 1 || $nonceId < 1) return false;
        $currTime   = CommTime::getTimeStamp();
        if($this->DbAuto->getDataNum('UPDATE '.$this->DbAuto->getTableNameAll('adm_user_token').' SET utnr_delete=1, utnr_update_time='.$currTime.' WHERE utnr_nonce='.$nonceId.' AND auir_id='.$admUserId.' AND utnr_delete=0') < 1) return false;
        AuthData::delCacheTokenKeyData(AuthData::getTokenKeyByNonce($nonceId), $admUserId);
        return true;
    }

    /**
     * @param int $admUserId
     * @param int $nonceId
     * @return int
     * 获取续期令牌记录Id
     */
    public function getRenewUserTokenId(int $admUserId, int $nonceId):int
    {
        if($admUserId < 1 || $nonceId < 1) return 0;
        $currTime   = CommTime::getTimeStamp();
        return $this->DbAuto->getDataInt('SELECT utnr_id FROM '.$this->DbAuto->getTableNameAll('adm_user_token').' WHERE utnr_nonce='.$nonceId.' AND auir_id='.$admUserId.' AND utnr_delete=0 AND utnr_expire_time>'.$currTime.' AND utnr_renew_time=0', 'utnr_id');
    }

    /**
     * @param int $admUserId
     * @param int $nonceIdOld
     * @param int $utnrId
     * @param string $devId
     * @param string $platform
     * @param TokenVO|null $TokenVO
     * @return bool
     * 续期令牌
     */
    public function renewUserToken(int $admUserId, int $nonceIdOld, int $utnrId, string $devId, string $platform, ?TokenVO &$TokenVO):bool
    {
        if($admUserId < 1 || $nonceIdOld < 1 || $utnrId < 1) return false;
        $currTime               = CommTime::getTimeStamp();
        $IdxIp                  = IdxIp::tag();
        $currIpStr              = '';
        $currIpIntStr           = $IdxIp->getReqIpNumStr([], CommNet::REQ_FORWARD_FOR_TYPE_BEFORE, true, $currIpStr);
        $ddptId                 = 0;
        $dupId                  = 0;
        $authSuper              = false;
        $authStr                = AccountCtl::tag()->getAdmUserReqString($admUserId, $authSuper);
        $tokenData              = AuthData::generateNewToken($admUserId, $authStr, $devId, $platform, $authSuper);
        $tokenStr               = $tokenData['tokenStr'];
        $expireTime             = $tokenData['expireTime'];
        $renewTime              = $tokenData['renewTime'];
        $nonceInt               = $tokenData['nonceInt'];
        $tokenKey               = $tokenData['tokenKey'];
        if(strlen($tokenStr) < 32 || $expireTime < $currTime || $renewTime < $currTime || $nonceInt < 1 || strlen($tokenKey) !== 16) return false;
        $oldExpireTime          = 60;   // 原令牌有效期更新
        $this->DbAuto->startTransaction();
        $sql                    = 'UPDATE '.$this->DbAuto->getTableNameAll('adm_user_token').' SET utnr_renew_time='.$currTime.', utnr_expire_time='.($currTime+$oldExpireTime).' WHERE utnr_id='.$utnrId.' AND utnr_nonce='.$nonceIdOld.' AND auir_id='.$admUserId.' AND utnr_delete=0 AND utnr_expire_time>'.$currTime.' AND utnr_renew_time=0';
        if($this->DbAuto->getDataNum($sql) < 1){
            $this->DbAuto->backTransaction();
            return false;
        }
        // 写入新令牌
        $sql                    = 'INSERT INTO '.$this->DbAuto->getTableNameAll('adm_user_token').' SET auir_id='.$admUserId.', utnr_nonce='.$nonceInt.', dup_id='.$dupId.', ddpt_id='.$ddptId.', utnr_ip='.$currIpIntStr.', utnr_expire_time='.$expireTime.', utnr_id_renew='.$utnrId.', utnr_renew_time=0, utnr_delete=0, utnr_create_time='.$currTime.', utnr_update_time='.$currTime;
        if($this->DbAuto->getDataId($sql) < 1){
            $this->DbAuto->backTransaction();
            return false;
        }
        // 更新登入记录
        $sql                    = 'UPDATE '.$this->DbAuto->getTableNameAll('adm_user_record').' SET auir_last_sign_ip='.$currIpIntStr.', auir_last_sign_time='.$currTime.', auir_last_sign_num=auir_last_sign_num+1, auir_update_time='.$currTime.' WHERE auir_id='.$admUserId.' AND auir_delete=0';
        if($this->DbAuto->getDataNum($sql) < 1){
            $this->DbAuto->backTransaction();
            return false;
        }
        $this->DbAuto->commitTransaction();
        // 设置原令牌缓存有效期
        AuthData::ttlCacheTokenKeyData(AuthData::getTokenKeyByNonce($nonceIdOld), $admUserId, $oldExpireTime);
        $TokenVO                = new TokenVO();
        $TokenVO->setTokenStr($tokenStr);
        $TokenVO->setExpireTime($expireTime);
        $TokenVO->setRenewTime($renewTime);
        return true;
    }
}